package com.ra.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Index;

/**
 * 地址结构编码
 * 
 * @author Jerry.Feng Date: 2015-4-21
 *
 */
@Entity
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class AddressCode {
	
	public final static Integer LEVEL_PROVINCE = 1;
	public final static Integer LEVEL_CITY = 2;
	public final static Integer LEVEL_DISTRICT = 3;
	public final static Integer LEVEL_COUNTRY = 4;
	public final static Integer LEVEL_VILLAGE = 5;
	
	private Integer id;
	
	// 地址编码, 兼容旧的area.xml
	private Integer code;
	
	// 地址名
	private String name;
	
	// 行政层级 (1-5)(省,市,区,乡镇,村), 方便查询的冗余字段
	private Integer level;
	
	// 父级, 省为最顶级, 其parent为空
	private AddressCode parent;
	
	// transient, 下级行政区域
	private List<AddressCode> subAddressCodes;
	
	// transient, 以'_'拼接的完整编码
	private String fullCode;
	
	// 拼音名称
	private String pinyinName;
	
	// 拼音简写名称
	private String pinyinShortName;
	
	// 经度
	private Double longitude;

	// 维度
	private Double latitude;
	
	// transient, 距离
	private Double distance;

	@Id
	@GeneratedValue
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public Integer getCode() {
		return code;
	}
	
	@Column(length=100)
	@Index(name="idx_ra_addresscode_pinyinName",columnNames={"pinyinName","pinyinShortName"})
	public String getPinyinName() {
		return pinyinName;
	}

	public void setPinyinName(String pinyinName) {
		this.pinyinName = pinyinName;
	}

	@Column(length=30)
	public String getPinyinShortName() {
		return pinyinShortName;
	}

	public void setPinyinShortName(String pinyinShortName) {
		this.pinyinShortName = pinyinShortName;
	}

	@Transient
	public String getFullCode() {
		List<AddressCode> addressCodes = new ArrayList<>(this.level);
		AddressCode addressCode = this;
		while (addressCode != null) {		// addressCode.getParent() != null
			addressCodes.add(addressCode);
			addressCode = addressCode.getParent();
		}
		Collections.reverse(addressCodes);
		
		StringBuilder sb = new StringBuilder();
		sb.append('1');
		for (AddressCode code : addressCodes) {
			sb.append('_').append(code.getCode());
		}
		return sb.toString();
	}

	public void setFullCode(String stringCode) {
		this.fullCode = stringCode;
	}

	public void setCode(Integer code) {
		this.code = code;
	}

	public Integer getLevel() {
		return level;
	}

	public void setLevel(Integer level) {
		this.level = level;
	}

	@Index(name="idx_ra_addresscode_name")
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	@Transient
	public String getFullName() {
		List<AddressCode> addressCodes = new ArrayList<>(this.level);
		AddressCode addressCode = this;
		while (addressCode != null) {		// addressCode.getParent() != null
			addressCodes.add(addressCode);
			addressCode = addressCode.getParent();
		}
		Collections.reverse(addressCodes);
		
		StringBuilder sb = new StringBuilder();
		for (AddressCode code : addressCodes) {
			sb.append(code.getName());
		}
		return sb.toString();
	}

	@ManyToOne
	public AddressCode getParent() {
		return parent;
	}

	public void setParent(AddressCode parent) {
		this.parent = parent;
	}

	@Transient
	public List<AddressCode> getSubAddressCodes() {
		return subAddressCodes;
	}

	public void setSubAddressCodes(List<AddressCode> subAddressCodes) {
		this.subAddressCodes = subAddressCodes;
	}

	@Deprecated
	public Integer getCodeByLevel(int level) {
		if (level > this.level) {
			return null;
		} else if (level == this.level) {
			return code;
		} else {
			// find the parent code
			AddressCode parent = this.parent;
			while (parent != null) {
				if (parent.level == level) {
					return parent.code;
				}
				parent = parent.getParent();
			}
			return null;
		}
	}

	public Double getLongitude() {
		return longitude;
	}

	public void setLongitude(Double longitude) {
		this.longitude = longitude;
	}

	public Double getLatitude() {
		return latitude;
	}

	public void setLatitude(Double latitude) {
		this.latitude = latitude;
	}
	
	@Transient
	public Double getDistance() {
		return distance;
	}

	public void setDistance(Double distance) {
		this.distance = distance;
	}
}
